import 'dart:async';

class EventBus {
  static final EventBus _syncInstance = EventBus._sync();
  static final EventBus _asyncInstance = EventBus._async();
  StreamController? _controller;
  final _stickyEvents = <Type, dynamic>{};

  factory EventBus({bool sync = false}) {
    return sync ? _syncInstance : _asyncInstance;
  }

  EventBus._sync() {
    _controller ??= StreamController.broadcast(sync: true);
  }

  EventBus._async() {
    _controller ??= StreamController.broadcast();
  }

  Stream<T> subscribe<T>() {
    return _controller!.stream.where((e) => e is T).cast<T>();
  }

  Stream<T> subscribeSticky<T>() async* {
    var stream = _controller!.stream.where((e) => e is T).cast<T>();
    if (_stickyEvents.containsKey(T)) {
      yield _stickyEvents[T];
    }
    yield* stream;
  }

  publish(dynamic event) {
    if (event != null) {
      _stickyEvents[event.runtimeType] = event;
      _controller!.add(event);
    }
  }
}
